﻿using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Core.Address;
using HslCommunication.Core.Net;
using HslCommunication.LogNet;
using HslCommunication.Reflection;

namespace HslCommunication.Profinet.Siemens
{
	/// <summary>
	/// <b>[商业授权]</b> 西门子的Fetch/Write协议的虚拟PLC，可以用来调试通讯，也可以实现一个虚拟的PLC功能，从而开发一套带虚拟环境的上位机系统，可以用来演示，测试。<br />
	/// <b>[Authorization]</b> The virtual PLC of Siemens Fetch/Write protocol can be used for debugging communication, and can also realize a virtual PLC function, so as to develop a set of upper computer system with virtual environment, which can be used for demonstration and testing.
	/// </summary>
	/// <remarks>
	/// 本虚拟服务器的使用需要企业商业授权，否则只能运行24小时。本协议实现的虚拟PLC服务器，主要支持I,Q,M,DB块的数据读写操作，例如 M100, DB1.100，服务器端也可以对位进行读写操作，例如M100.1，DB1.100.2；
	/// 但是不支持连接的远程客户端对位进行操作。
	/// </remarks>
	/// <example>
	/// 地址支持的列表如下：
	/// <list type="table">
	///   <listheader>
	///     <term>地址名称</term>
	///     <term>地址代号</term>
	///     <term>示例</term>
	///     <term>地址进制</term>
	///     <term>字操作</term>
	///     <term>位操作</term>
	///     <term>备注</term>
	///   </listheader>
	///   <item>
	///     <term>中间寄存器</term>
	///     <term>M</term>
	///     <term>M100,M200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>输入寄存器</term>
	///     <term>I</term>
	///     <term>I100,I200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>输出寄存器</term>
	///     <term>Q</term>
	///     <term>Q100,Q200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>DB块寄存器</term>
	///     <term>DB</term>
	///     <term>DB1.100,DB1.200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>V寄存器</term>
	///     <term>V</term>
	///     <term>V100,V200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term>V寄存器本质就是DB块1</term>
	///   </item>
	/// </list>
	/// 本虚拟的PLC共有4个DB块，DB1.X, DB2.X, DB3.X, 和其他DB块。对于远程客户端的读写长度，暂时没有限制。
	/// </example>
	// Token: 0x0200004A RID: 74
	public class SiemensFetchWriteServer : NetworkDataServerBase
	{
		/// <summary>
		/// 实例化一个S7协议的服务器，支持I，Q，M，DB1.X, DB2.X, DB3.X 数据区块的读写操作<br />
		/// Instantiate a server with S7 protocol, support I, Q, M, DB1.X data block read and write operations
		/// </summary>
		// Token: 0x06000610 RID: 1552 RVA: 0x0001C068 File Offset: 0x0001A268
		public SiemensFetchWriteServer()
		{
			this.inputBuffer = new SoftBuffer(65536);
			this.outputBuffer = new SoftBuffer(65536);
			this.memeryBuffer = new SoftBuffer(65536);
			this.db1BlockBuffer = new SoftBuffer(65536);
			this.db2BlockBuffer = new SoftBuffer(65536);
			this.db3BlockBuffer = new SoftBuffer(65536);
			this.dbOtherBlockBuffer = new SoftBuffer(65536);
			this.counterBuffer = new SoftBuffer(65536);
			this.timerBuffer = new SoftBuffer(65536);
			base.WordLength = 2;
			base.ByteTransform = new ReverseBytesTransform();
		}

		// Token: 0x06000611 RID: 1553 RVA: 0x0001C124 File Offset: 0x0001A324
		private OperateResult<SoftBuffer> GetDataAreaFromS7Address(S7AddressData s7Address)
		{
			OperateResult<SoftBuffer> result;
			switch (s7Address.DataCode)
			{
			case 129:
				result = OperateResult.CreateSuccessResult<SoftBuffer>(this.inputBuffer);
				break;
			case 130:
				result = OperateResult.CreateSuccessResult<SoftBuffer>(this.outputBuffer);
				break;
			case 131:
				result = OperateResult.CreateSuccessResult<SoftBuffer>(this.memeryBuffer);
				break;
			case 132:
			{
				bool flag = s7Address.DbBlock == 1;
				if (flag)
				{
					result = OperateResult.CreateSuccessResult<SoftBuffer>(this.db1BlockBuffer);
				}
				else
				{
					bool flag2 = s7Address.DbBlock == 2;
					if (flag2)
					{
						result = OperateResult.CreateSuccessResult<SoftBuffer>(this.db2BlockBuffer);
					}
					else
					{
						bool flag3 = s7Address.DbBlock == 3;
						if (flag3)
						{
							result = OperateResult.CreateSuccessResult<SoftBuffer>(this.db3BlockBuffer);
						}
						else
						{
							result = OperateResult.CreateSuccessResult<SoftBuffer>(this.dbOtherBlockBuffer);
						}
					}
				}
				break;
			}
			default:
				result = new OperateResult<SoftBuffer>(StringResources.Language.NotSupportedDataType);
				break;
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensS7Net.Read(System.String,System.UInt16)" />
		// Token: 0x06000612 RID: 1554 RVA: 0x0001C204 File Offset: 0x0001A404
		[HslMqttApi("ReadByteArray", "")]
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			OperateResult<S7AddressData> operateResult = S7AddressData.ParseFrom(address, length);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				OperateResult<SoftBuffer> dataAreaFromS7Address = this.GetDataAreaFromS7Address(operateResult.Content);
				bool flag2 = !dataAreaFromS7Address.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<byte[]>(dataAreaFromS7Address);
				}
				else
				{
					result = OperateResult.CreateSuccessResult<byte[]>(dataAreaFromS7Address.Content.GetBytes(operateResult.Content.AddressStart / 8, (int)length));
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensS7Net.Write(System.String,System.Byte[])" />
		// Token: 0x06000613 RID: 1555 RVA: 0x0001C278 File Offset: 0x0001A478
		[HslMqttApi("WriteByteArray", "")]
		public override OperateResult Write(string address, byte[] value)
		{
			OperateResult<S7AddressData> operateResult = S7AddressData.ParseFrom(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				OperateResult<SoftBuffer> dataAreaFromS7Address = this.GetDataAreaFromS7Address(operateResult.Content);
				bool flag2 = !dataAreaFromS7Address.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<byte[]>(dataAreaFromS7Address);
				}
				else
				{
					dataAreaFromS7Address.Content.SetBytes(value, operateResult.Content.AddressStart / 8);
					result = OperateResult.CreateSuccessResult();
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensS7Net.ReadByte(System.String)" />
		// Token: 0x06000614 RID: 1556 RVA: 0x0001C2EB File Offset: 0x0001A4EB
		[HslMqttApi("ReadByte", "")]
		public OperateResult<byte> ReadByte(string address)
		{
			return ByteTransformHelper.GetResultFromArray<byte>(this.Read(address, 1));
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensS7Net.Write(System.String,System.Byte)" />
		// Token: 0x06000615 RID: 1557 RVA: 0x0001C2FA File Offset: 0x0001A4FA
		[HslMqttApi("WriteByte", "")]
		public OperateResult Write(string address, byte value)
		{
			return this.Write(address, new byte[]
			{
				value
			});
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensS7Net.ReadBool(System.String)" />
		// Token: 0x06000616 RID: 1558 RVA: 0x0001C310 File Offset: 0x0001A510
		[HslMqttApi("ReadBool", "")]
		public override OperateResult<bool> ReadBool(string address)
		{
			OperateResult<S7AddressData> operateResult = S7AddressData.ParseFrom(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult<bool> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<bool>(operateResult);
			}
			else
			{
				OperateResult<SoftBuffer> dataAreaFromS7Address = this.GetDataAreaFromS7Address(operateResult.Content);
				bool flag2 = !dataAreaFromS7Address.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<bool>(dataAreaFromS7Address);
				}
				else
				{
					result = OperateResult.CreateSuccessResult<bool>(dataAreaFromS7Address.Content.GetBool(operateResult.Content.AddressStart));
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensS7Net.Write(System.String,System.Boolean)" />
		// Token: 0x06000617 RID: 1559 RVA: 0x0001C380 File Offset: 0x0001A580
		[HslMqttApi("WriteBool", "")]
		public override OperateResult Write(string address, bool value)
		{
			OperateResult<S7AddressData> operateResult = S7AddressData.ParseFrom(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<SoftBuffer> dataAreaFromS7Address = this.GetDataAreaFromS7Address(operateResult.Content);
				bool flag2 = !dataAreaFromS7Address.IsSuccess;
				if (flag2)
				{
					result = dataAreaFromS7Address;
				}
				else
				{
					dataAreaFromS7Address.Content.SetBool(value, operateResult.Content.AddressStart);
					result = OperateResult.CreateSuccessResult();
				}
			}
			return result;
		}

		/// <inheritdoc />
		// Token: 0x06000618 RID: 1560 RVA: 0x0001C3E8 File Offset: 0x0001A5E8
		protected override void ThreadPoolLoginAfterClientCheck(Socket socket, IPEndPoint endPoint)
		{
			AppSession appSession = new AppSession();
			appSession.IpEndPoint = endPoint;
			appSession.WorkSocket = socket;
			try
			{
				socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.SocketAsyncCallBack), appSession);
				base.AddClient(appSession);
			}
			catch
			{
				socket.Close();
				ILogNet logNet = base.LogNet;
				if (logNet != null)
				{
					logNet.WriteDebug(this.ToString(), string.Format(StringResources.Language.ClientOfflineInfo, endPoint));
				}
			}
		}

		// Token: 0x06000619 RID: 1561 RVA: 0x0001C47C File Offset: 0x0001A67C
		[DebuggerStepThrough]
		private void SocketAsyncCallBack(IAsyncResult ar)
		{
			SiemensFetchWriteServer.<SocketAsyncCallBack>d__9 <SocketAsyncCallBack>d__ = new SiemensFetchWriteServer.<SocketAsyncCallBack>d__9();
			<SocketAsyncCallBack>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
			<SocketAsyncCallBack>d__.<>4__this = this;
			<SocketAsyncCallBack>d__.ar = ar;
			<SocketAsyncCallBack>d__.<>1__state = -1;
			<SocketAsyncCallBack>d__.<>t__builder.Start<SiemensFetchWriteServer.<SocketAsyncCallBack>d__9>(ref <SocketAsyncCallBack>d__);
		}

		// Token: 0x0600061A RID: 1562 RVA: 0x0001C4BC File Offset: 0x0001A6BC
		private SoftBuffer GetBufferFromCommand(byte[] command)
		{
			bool flag = command[8] == 2;
			SoftBuffer result;
			if (flag)
			{
				result = this.memeryBuffer;
			}
			else
			{
				bool flag2 = command[8] == 3;
				if (flag2)
				{
					result = this.inputBuffer;
				}
				else
				{
					bool flag3 = command[8] == 4;
					if (flag3)
					{
						result = this.outputBuffer;
					}
					else
					{
						bool flag4 = command[8] == 1;
						if (flag4)
						{
							bool flag5 = command[9] == 1;
							if (flag5)
							{
								result = this.db1BlockBuffer;
							}
							else
							{
								bool flag6 = command[9] == 2;
								if (flag6)
								{
									result = this.db2BlockBuffer;
								}
								else
								{
									bool flag7 = command[9] == 3;
									if (flag7)
									{
										result = this.db3BlockBuffer;
									}
									else
									{
										result = this.dbOtherBlockBuffer;
									}
								}
							}
						}
						else
						{
							bool flag8 = command[8] == 6;
							if (flag8)
							{
								result = this.counterBuffer;
							}
							else
							{
								bool flag9 = command[8] == 7;
								if (flag9)
								{
									result = this.timerBuffer;
								}
								else
								{
									result = null;
								}
							}
						}
					}
				}
			}
			return result;
		}

		// Token: 0x0600061B RID: 1563 RVA: 0x0001C594 File Offset: 0x0001A794
		private byte[] ReadByMessage(byte[] command)
		{
			SoftBuffer bufferFromCommand = this.GetBufferFromCommand(command);
			int index = (int)command[10] * 256 + (int)command[11];
			int num = (int)command[12] * 256 + (int)command[13];
			bool flag = bufferFromCommand == null;
			byte[] result;
			if (flag)
			{
				result = this.PackCommandResponse(6, 1, null);
			}
			else
			{
				bool flag2 = command[8] == 1 || command[8] == 6 || command[8] == 7;
				if (flag2)
				{
					result = this.PackCommandResponse(6, 0, bufferFromCommand.GetBytes(index, num * 2));
				}
				else
				{
					result = this.PackCommandResponse(6, 0, bufferFromCommand.GetBytes(index, num));
				}
			}
			return result;
		}

		// Token: 0x0600061C RID: 1564 RVA: 0x0001C628 File Offset: 0x0001A828
		private byte[] WriteByMessage(byte[] command)
		{
			SoftBuffer bufferFromCommand = this.GetBufferFromCommand(command);
			int destIndex = (int)command[10] * 256 + (int)command[11];
			int num = (int)command[12] * 256 + (int)command[13];
			bool flag = bufferFromCommand == null;
			byte[] result;
			if (flag)
			{
				result = this.PackCommandResponse(4, 1, null);
			}
			else
			{
				bool flag2 = command[8] == 1 || command[8] == 6 || command[8] == 7;
				if (flag2)
				{
					bool flag3 = num != (command.Length - 16) / 2;
					if (flag3)
					{
						result = this.PackCommandResponse(4, 1, null);
					}
					else
					{
						bufferFromCommand.SetBytes(command.RemoveBegin(16), destIndex);
						result = this.PackCommandResponse(4, 0, null);
					}
				}
				else
				{
					bool flag4 = num != command.Length - 16;
					if (flag4)
					{
						result = this.PackCommandResponse(4, 1, null);
					}
					else
					{
						bufferFromCommand.SetBytes(command.RemoveBegin(16), destIndex);
						result = this.PackCommandResponse(4, 0, null);
					}
				}
			}
			return result;
		}

		// Token: 0x0600061D RID: 1565 RVA: 0x0001C710 File Offset: 0x0001A910
		private byte[] PackCommandResponse(byte opCode, byte err, byte[] data)
		{
			bool flag = data == null;
			if (flag)
			{
				data = new byte[0];
			}
			byte[] array = new byte[16 + data.Length];
			array[0] = 83;
			array[1] = 53;
			array[2] = 16;
			array[3] = 1;
			array[4] = 3;
			array[5] = opCode;
			array[6] = 15;
			array[7] = 3;
			array[8] = err;
			array[9] = byte.MaxValue;
			array[10] = 7;
			bool flag2 = data.Length != 0;
			if (flag2)
			{
				data.CopyTo(array, 16);
			}
			return array;
		}

		/// <inheritdoc />
		// Token: 0x0600061E RID: 1566 RVA: 0x0001C788 File Offset: 0x0001A988
		protected override void LoadFromBytes(byte[] content)
		{
			bool flag = content.Length < 589824;
			if (flag)
			{
				throw new Exception("File is not correct");
			}
			this.inputBuffer.SetBytes(content, 0, 0, 65536);
			this.outputBuffer.SetBytes(content, 65536, 0, 65536);
			this.memeryBuffer.SetBytes(content, 131072, 0, 65536);
			this.db1BlockBuffer.SetBytes(content, 196608, 0, 65536);
			this.db2BlockBuffer.SetBytes(content, 262144, 0, 65536);
			this.db3BlockBuffer.SetBytes(content, 327680, 0, 65536);
			this.dbOtherBlockBuffer.SetBytes(content, 393216, 0, 65536);
			this.counterBuffer.SetBytes(content, 458752, 0, 65536);
			this.timerBuffer.SetBytes(content, 524288, 0, 65536);
		}

		/// <inheritdoc />
		// Token: 0x0600061F RID: 1567 RVA: 0x0001C884 File Offset: 0x0001AA84
		protected override byte[] SaveToBytes()
		{
			byte[] array = new byte[589824];
			Array.Copy(this.inputBuffer.GetBytes(), 0, array, 0, 65536);
			Array.Copy(this.outputBuffer.GetBytes(), 0, array, 65536, 65536);
			Array.Copy(this.memeryBuffer.GetBytes(), 0, array, 131072, 65536);
			Array.Copy(this.db1BlockBuffer.GetBytes(), 0, array, 196608, 65536);
			Array.Copy(this.db2BlockBuffer.GetBytes(), 0, array, 262144, 65536);
			Array.Copy(this.db3BlockBuffer.GetBytes(), 0, array, 327680, 65536);
			Array.Copy(this.dbOtherBlockBuffer.GetBytes(), 0, array, 393216, 65536);
			Array.Copy(this.counterBuffer.GetBytes(), 0, array, 458752, 65536);
			Array.Copy(this.timerBuffer.GetBytes(), 0, array, 524288, 65536);
			return array;
		}

		/// <inheritdoc />
		// Token: 0x06000620 RID: 1568 RVA: 0x0001C9A4 File Offset: 0x0001ABA4
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				SoftBuffer softBuffer = this.inputBuffer;
				if (softBuffer != null)
				{
					softBuffer.Dispose();
				}
				SoftBuffer softBuffer2 = this.outputBuffer;
				if (softBuffer2 != null)
				{
					softBuffer2.Dispose();
				}
				SoftBuffer softBuffer3 = this.memeryBuffer;
				if (softBuffer3 != null)
				{
					softBuffer3.Dispose();
				}
				SoftBuffer softBuffer4 = this.db1BlockBuffer;
				if (softBuffer4 != null)
				{
					softBuffer4.Dispose();
				}
				SoftBuffer softBuffer5 = this.db2BlockBuffer;
				if (softBuffer5 != null)
				{
					softBuffer5.Dispose();
				}
				SoftBuffer softBuffer6 = this.db3BlockBuffer;
				if (softBuffer6 != null)
				{
					softBuffer6.Dispose();
				}
				SoftBuffer softBuffer7 = this.dbOtherBlockBuffer;
				if (softBuffer7 != null)
				{
					softBuffer7.Dispose();
				}
			}
			base.Dispose(disposing);
		}

		/// <inheritdoc />
		// Token: 0x06000621 RID: 1569 RVA: 0x0001CA42 File Offset: 0x0001AC42
		public override string ToString()
		{
			return string.Format("SiemensFetchWriteServer[{0}]", base.Port);
		}

		// Token: 0x04000195 RID: 405
		private SoftBuffer inputBuffer;

		// Token: 0x04000196 RID: 406
		private SoftBuffer outputBuffer;

		// Token: 0x04000197 RID: 407
		private SoftBuffer memeryBuffer;

		// Token: 0x04000198 RID: 408
		private SoftBuffer counterBuffer;

		// Token: 0x04000199 RID: 409
		private SoftBuffer timerBuffer;

		// Token: 0x0400019A RID: 410
		private SoftBuffer db1BlockBuffer;

		// Token: 0x0400019B RID: 411
		private SoftBuffer db2BlockBuffer;

		// Token: 0x0400019C RID: 412
		private SoftBuffer db3BlockBuffer;

		// Token: 0x0400019D RID: 413
		private SoftBuffer dbOtherBlockBuffer;

		// Token: 0x0400019E RID: 414
		private const int DataPoolLength = 65536;
	}
}
